package com.itheima.d2_reflect;

import org.junit.Test;
import java.lang.reflect.Field;

/**
 * 目标：掌握获取类的成员变量，并对其进行操作。
 *
 * 使用反射技术获取成员变量对象并使用
 * 第一步：获得class对象
 * 第二步：获得Field对象
 * 第三步：赋值或者获取值
 *
 * 使用反射技术获取成员变量对象并使用
 * 反射的第一步是先得到类对象，然后从类对象中获取类的成分对象。
 * Class类中用于获取成员变量的方法
 *      方法
 * Field[] getFields()                      返回类的所有成员变量对象的数组（只能拿public的）
 * Field[] getDeclaredFields()              返回类的所有成员变量对象的数组，存在就能拿到
 * Field getField(String name)              返回类的单个成员变量对象（只能拿public的）
 * Field getDeclaredField(String name)      返回类的单个成员变量对象，存在就能拿到
 *
 * 使用反射技术获取成员变量对象并使用
 * 获取成员变量的作用:
 * 依然是在某个对象中取值、赋值
 * Field类中用于取值、赋值的方法
 *          方法
 * void set(Object obj, Object value)：          赋值
 * Object get(Object obj)                       获取值
 * public void setAccessible(boolean flag)      设置为true，表示禁止检查访问控制（暴力反射）
 * 如果某成员变量是非public的，需要打开权限（暴力反射），然后再取值、赋值
 *
 * 磊哥：这种代码风格是我们将来学习框架的时候做准备的，现在大家理解不了这种脱裤子放屁的代码风格是正常的
 *      现在先记住这种代码风格就行了，以后遇到了自然就知道它的作用了
 */

public class Test3Field {
    @Test
    public void testGetFields() throws Exception {
        // 1、反射第一步：必须是先得到类的Class对象  （磊哥：你拿到类的class对象，就相当于得到了这个类，才可以去拿类里面的成员）
        Class c = Cat.class;
        // 2、获取类的全部成员变量。放在一个成员变量数组里面
        Field[] fields = c.getDeclaredFields();
        // 3、遍历这个成员变量数组
        for (Field field : fields) {
            //拿到成员变量的名字和类型
            System.out.println(field.getName() +  "---> "+ field.getType());
        }

        System.out.println("----------------------------------------");

        // 4、定位某个成员变量
        Field fName = c.getDeclaredField("name");   //Java担心成员变量名字写错了，有异常直接抛出
        System.out.println(fName.getName() + "--->" + fName.getType());

        Field fAge = c.getDeclaredField("age");
        System.out.println(fAge.getName() + "--->" + fAge.getType());

        // 赋值   void set(Object obj, Object value)：成员变量不能独立存在，属于某个对象的成员变量，所以要先new一个对象
        //把cat类的无参构造器从private改为public，其实用前面的拿到构造器对象创建类对象也可以。
        //但是cat类里面的name成员变量是private修饰，所以会报错：权限访问异常。所以也要用到setAccessible方法打开权限
        Cat cat = new Cat();
        fName.setAccessible(true); // 禁止访问控制权限
        fName.set(cat, "卡菲猫");
        System.out.println(cat);

        //Object get(Object obj)   获取值
        String name = (String) fName.get(cat);      //获取cat这个对象对应的这个成员变量的值
        System.out.println(name);
    }
}
